//
//@author jltxseo
// Created by junlintianxia on 2019/4/23.
//
#include <jni.h>
#include <android/log.h>
#include <iostream>
#include "DataObjProvider.h"

using namespace std;

#define LOG_TAG "ndk.out.c"
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)

/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    getDataBeanInfo
 * Signature: ()Lcom/xq/jltx/bean/DataBean;
 */
JNIEXPORT jobject JNICALL Java_com_xq_jltx_javajni_DataObjProvider_getDataBeanInfo
        (JNIEnv *env, jclass cls) {
    //包的描述符，是com/xq/jltx/bean/DataBean
    //获取到class的引用，并且该类不能混淆
    jclass dataBeanCls = env->FindClass("com/xq/jltx/bean/DataBean");
    //获得得该类型的构造函数  函数名为 <init> 返回类型必须为 void 即 V
    jmethodID constructorId = env->GetMethodID(dataBeanCls, "<init>", "(Ljava/lang/String;)V");
    //构造一个jString对象
    char *c_ptr_name = "I come from Native";
    //构造一个jstring对象
    jstring cName = env->NewStringUTF(c_ptr_name);

    //传入构造函数的id构造一个对象
    jobject dataObj = env->NewObject(dataBeanCls, constructorId, cName);

    //获取dataId的fieldID
    jfieldID dataFieldId = env->GetFieldID(dataBeanCls, "dataId", "J");
    if (dataFieldId == NULL) {
        LOGD("get name dataId id erro \n");
    }
    //设置dataId的属性值
    long longDataId = 1233567;
    env->SetLongField(dataObj, dataFieldId, longDataId);

    //通过方法设置age属性
    jmethodID ageMethodId = env->GetMethodID(dataBeanCls, "setAge", "(I)V");
    if (ageMethodId == 0) {
        LOGD("setAge MethodId id erro \n");
    }

    int age = 27;
    //调用setAge这个方法
    env->CallVoidMethod(dataObj, ageMethodId, age);

    jfieldID isLocalId = env->GetFieldID(dataBeanCls, "isLocal", "Z");
    if (isLocalId == NULL) {
        LOGD("get isLocal id erro \n");
    }

    bool isLocal = true;
    env->SetBooleanField(dataObj, isLocalId, isLocal);

    //通过方法设置age属性
    jmethodID dataNameMethodId = env->GetMethodID(dataBeanCls, "setDataName",
                                                  "(Ljava/lang/String;)V");
    if (dataNameMethodId == 0) {
        LOGD("setDataName MethodId id erro \n");
    }

    //构造一个jString对象
    char *c_ptr_name1 = "I come from Native1";
    //构造一个jstring对象
    jstring cName1 = env->NewStringUTF(c_ptr_name1);

    //调用setDataName这个私有方法
    env->CallVoidMethod(dataObj, dataNameMethodId, cName1);

    return dataObj;
}

/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    setDataBeanInfo
 * Signature: (Lcom/xq/jltx/bean/DataBean;)V
 */
JNIEXPORT void JNICALL Java_com_xq_jltx_javajni_DataObjProvider_setDataBeanInfo
        (JNIEnv *env, jclass cls, jobject dataObj) {
    //获取传入对象的class的引用
    jclass dataBeanCls = env->GetObjectClass(dataObj);
    if (dataBeanCls == NULL) {
        LOGD("get dataBeanCls erro \n");
    }

    //获取dataId的fieldID
    jfieldID dataFieldId = env->GetFieldID(dataBeanCls, "dataId", "J");
    if (dataFieldId == NULL) {
        LOGD("get dataId id erro \n");
    }

    //获取属性值
    jlong dataId = env->GetLongField(dataObj, dataFieldId);

    jfieldID dataNameFieldId = env->GetFieldID(dataBeanCls, "dataName", "Ljava/lang/String;");
    if (dataNameFieldId == NULL) {
        LOGD("get dataName id erro \n");
    }

    jstring dataName = (jstring) env->GetObjectField(dataObj, dataNameFieldId);
    const char *c_dataName = env->GetStringUTFChars(dataName, NULL);
    LOGD("dataId:%d,dataName:%s", dataId, c_dataName);
}

/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    getListDataBeans
 * Signature: ()Ljava/util/ArrayList;
 */
JNIEXPORT jobject JNICALL Java_com_xq_jltx_javajni_DataObjProvider_getListDataBeans
        (JNIEnv *env, jclass cls) {
    //获取ArrayList类的引用class
    //javap -c -s java.util.ArrayList可以打印ArrayList的签名
    jclass listCls = env->FindClass("java/util/ArrayList");
    if (listCls == NULL) {
        LOGD("get listCls erro \n");
    }
    //获得ArrayList类的无参构造函数的id
    jmethodID listConstructId = env->GetMethodID(listCls, "<init>", "()V");
    //构建一个new ArrayList对象
    jobject listObj = env->NewObject(listCls, listConstructId);
    //或得Arraylist类中的 add()方法ID，其方法原型为： boolean add(Object object) ;
    jmethodID addMethodId = env->GetMethodID(listCls, "add", "(Ljava/lang/Object;)Z");

    //包的描述符，是com/xq/jltx/bean/DataBean
    //两种类型都可以获取到class的引用，并且该类不能混淆
    jclass dataBeanCls = env->FindClass("com/xq/jltx/bean/DataBean");
    //获得得该类型的构造函数  函数名为 <init> 返回类型必须为 void 即 V
    jmethodID constructorId = env->GetMethodID(dataBeanCls, "<init>", "(Ljava/lang/String;)V");

    for (int i = 0; i < 5; ++i) {
        //构造一个jString对象
        char *c_ptr_name = "I 来自 Native";
        //先转成string后通过to_string拼接i
        string ptrName = c_ptr_name + to_string(i);
        // string 转 char*
        const char *chardata = ptrName.c_str();
        //构造一个jstring对象
        jstring cName = env->NewStringUTF(chardata);
        //传入构造函数的id构造一个对象
        jobject dataObj = env->NewObject(dataBeanCls, constructorId, cName);
        //调用add方法添加到ArrayList
        env->CallBooleanMethod(listObj, addMethodId, dataObj);
    }
    return listObj;


}

/* This code is illegal */
jclass stringClass = NULL;
/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    testLocalRefFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_xq_jltx_javajni_DataObjProvider_testLocalRefFromJNI
        (JNIEnv *env, jclass cls){
    jmethodID cid;
    jcharArray elemArr;
    jstring result;
    if (stringClass == NULL) {
        stringClass = env->FindClass("java/lang/String");
        if (stringClass == NULL) {
            return NULL; /* exception thrown */
        }
    }

    /* 不能直接使用GetMethodID来使用局部变量 */
    cid = (env)->GetMethodID(stringClass, "<init>", "([C)V");
    elemArr = (env)->NewCharArray( 10);
    result = (jstring)(env)->NewObject(stringClass, cid, elemArr);
    (env)->DeleteLocalRef( elemArr);

    return result;
}

jclass sStringClass = NULL;
/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    testGlobalRefFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_xq_jltx_javajni_DataObjProvider_testGlobalRefFromJNI
        (JNIEnv *env, jclass cls){
    jmethodID cid;
    jcharArray elemArr;
    jstring result;
    if (sStringClass == NULL) {
        jclass localCls= env ->FindClass("java/lang/String");
        if (localCls == NULL) {
            return NULL;
        }

        sStringClass = (jclass )env->NewGlobalRef(localCls);
        env->DeleteLocalRef(localCls);

        if (sStringClass == NULL) {
            return NULL; /* out of memory exception thrown */
        }

    }

    cid = (env)->GetMethodID(sStringClass, "<init>", "([C)V");
    elemArr = (env)->NewCharArray( 10);
    result = (jstring)(env)->NewObject(sStringClass, cid, elemArr);
    (env)->DeleteLocalRef( elemArr);

    return result;
}

jclass wStringClass = NULL;
/*
 * Class:     com_xq_jltx_javajni_DataObjProvider
 * Method:    testWeakRefFromJNI
 * Signature: ()Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_com_xq_jltx_javajni_DataObjProvider_testWeakRefFromJNI
        (JNIEnv *env, jclass cls){
    jmethodID cid;
    jcharArray elemArr;
    jstring result;
    if (wStringClass == NULL) {
        jclass localCls= env ->FindClass("java/lang/String");
        if (localCls == NULL) {
            return NULL;
        }

        wStringClass = (jclass )env->NewWeakGlobalRef(localCls);
        env->DeleteLocalRef(localCls);

    }

    /* 使用wStringClass的引用 */
    if (env->IsSameObject(wStringClass, NULL)) {
        LOGD("wStringClass is recycled");
        return NULL;
    } else {
        LOGD("wStringClass is not recycled");
    }

    cid = (env)->GetMethodID(wStringClass, "<init>", "([C)V");
    elemArr = (env)->NewCharArray( 10);
    result = (jstring)(env)->NewObject(wStringClass, cid, elemArr);
    (env)->DeleteLocalRef( elemArr);

    return result;
}

